﻿//-----------------------------------------------------------------------
// <copyright file="ProcessingManager.cs" company="FastNET Services">
//     Copyright (c) 2007-2009. All Rights Reserved.
// </copyright>
// <license>
//     GPLv2
// </license>
// <warranty>
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//     BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </warranty>
//-----------------------------------------------------------------------
#region Usings

using System;
using System.Collections.Generic;
using FastNET.CleanAct.Client.ClientEngine.Jobs;
using FastNET.CleanAct.Client.Configuration.ProcessingServices;
using FastNET.CleanAct.Client.Interfaces.Jobs;
using FastNET.CleanAct.Client.Interfaces.Managers;
using FastNET.CleanAct.Client.Interfaces.Services;
using FastNET.CleanAct.Client.Interfaces.Structures;
using FastNET.CleanAct.Common.Configuration.Configuration;
using FastNET.CleanAct.Common.Core;

#endregion

namespace FastNET.CleanAct.Client.ClientEngine.Managers.Processing
{
    /// <summary>
    /// Management class for handling all system related processing
    /// </summary>
    internal class ProcessingManager : IProcessingManager
    {
        #region Variables

        private readonly List<IService> _services;
        private readonly List<IJob> _processingJobs;

        #endregion

        #region CTor/DTor

        /// <summary>
        /// Initializes a new instance of the ProcessingManager class
        /// </summary>
        public ProcessingManager()
        {
            _services = new List<IService>();
            _processingJobs = new List<IJob>();
        }

        #endregion

        #region Public Processing Methods

        /// <summary>
        /// Handles processing given a specific group to use during processing
        /// </summary>
        /// <param name="processSet">ProcessingSet containing the information to process</param>
        public void Process(ProcessingSet processSet)
        {
            IList<Type> loadableServices = GetServicesToLoad(processSet.ProcessingGroup);
            IList<IService> loadedServices = LoadServices(loadableServices);

            _services.AddRange(loadedServices);

            JobConfigSettings settings = JobConfigSettings.LoadXml(processSet.XmlConfiguration);

            foreach (JobItem item in settings.Jobs)
            {
                Job job = new Job {JobName = item.Name, JobDescription = item.Description};

                _processingJobs.Add(job);

                foreach (ActionItem action in item.Actions)
                {
                    job.ActionList.Add(Guid.NewGuid(), new JobAction
                                            {
                                                ActionType = action.Type,
                                                Configuration = action.Value,
                                                Name = action.Name,
                                                RecursiveMode = (ActionRecursiveMode)action.RecursiveMode
                                            });                 
                }
            }

            RunServices();

            _processingJobs.Clear();
            _services.Clear();
        }

        #endregion

        #region Private Processing Methods

        /// <summary>
        /// Handles running of all the requested services
        /// </summary>
        private void RunServices()
        {
            foreach (IService service in _services)
            {
                service.JobList = _processingJobs;
                service.Process();
            }
        }

        #endregion

        #region Service Loading

        /// <summary>
        /// Gets a list of services from the configuration file based on the group to process
        /// </summary>
        /// <param name="processGroup">String with the group to get services for</param>
        /// <returns>IList of Types for all services related to the processing group in order</returns>
        private static IList<Type> GetServicesToLoad(string processGroup)
        {
            ProcessingServiceSection section = ProcessingServiceSection.GetConfigurationSection();
            SortedDictionary<byte, Type> loadableServices = new SortedDictionary<byte, Type>();

            foreach (ProcessingServiceElement element in section.Services)
            {
                if (!element.Enabled)
                {
                    continue;
                }

                foreach (ProcessingGroupElement group in element.Groups)
                {
                    if (!group.Enabled)
                    {
                        continue;
                    }

                    if (group.Name.ToLower() == processGroup.ToLower())
                    {
                        loadableServices.Add(group.Order, element.ServiceType);
                    }
                }
            }

            return new List<Type>(loadableServices.Values);
        }

        /// <summary>
        /// Takes a list of types and creates the instances of IServices for processing
        /// </summary>
        /// <param name="serviceTypes">Sorted IList of Type for all services to create</param>
        /// <returns>IList of IService for all services that will perform processing</returns>
        private static IList<IService> LoadServices(IList<Type> serviceTypes)
        {
            List<IService> loadedServices = new List<IService>();

            foreach (Type item in serviceTypes)
            {
                IService service = Activator.CreateInstance(item) as IService;

                loadedServices.Add(service);
            }

            return loadedServices;
        }

        #endregion
    }
}